package com.fcat.common.user.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fcat.common.user.constant.UserConstant;
import com.fcat.common.user.exception.FeignRequestException;
import com.fcat.springboot.mybatis.service.impl.TsuantoneBaseServiceImpl;
import com.fcat.base.common.util.ArrayUtil;
import com.fcat.springboot.mybatis.util.JsonUtil;
import com.fcat.base.common.util.StrUtil;
import com.fcat.common.user.entity.*;
import com.fcat.common.user.enums.StateCode;
import com.fcat.common.user.mapper.UserMapper;
import com.fcat.common.user.service.*;
import com.fcat.common.user.util.KeycloakUtil;
import com.fcat.common.user.vo.*;
import com.fcat.springboot.redis.service.RedisService;
import com.redis.common.TokenInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.*;


@Slf4j
@Service
public class UserServiceImpl extends TsuantoneBaseServiceImpl<UserMapper, User> implements UserService {

    @Value("${info.admin.systemUsername}")
    private String systemUsername;
    @Value("${info.admin.systemPassword}")
    private String systemPassword;

    @Value("${token.realm}")
    private String realm;
    @Value("${token.client}")
    private String client;
    @Value("${token.clientSecret}")
    private String clientSecret;
    @Value("${token.clienId}")
    private String clientId;

    @Autowired
    private CompanyService companyService;
    @Autowired
    private UserAuditService userAuditService;
    @Autowired
    private CertificateService certificateService;
    @Autowired
    private OrganizationService organizationService;
    @Autowired
    private UserRoleService userRoleService;
    @Autowired
    private PermissionService permissionService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private KeycloakService keycloakService;

    @Override
    public Integer updateByUsername(User user) {
        Example example = new Example(User.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("username", user.getUsername());
        return mapper.updateByExampleSelective(user, example);
    }

    /**
     * 修改密码
     */
    @Override
    public JSONObject updatePassword(String authorization, String username, String password) {
        User user = getUserByUsername(username);
        JSONObject jSONObjectParam = new JSONObject();
        jSONObjectParam.put("password", password);
        jSONObjectParam.put("userId", user.getKeycloakId());
//        return iAuthService.updatePasswordByUserId(Authorization, jSONObjectParam);
        return keycloakService.updatePassword(authorization,user.getUsername(),password);
    }


    /**
     * 1    修改用户信息
     * 2    修改证书信息
     * 3    修改角色权限
     * 4    修改密码
     * 5    如果没有keycloak
     * 6    创建用户
     * 7    添加权限
     *
     * @param Authorization
     * @param jsonObject
     * @return
     */
    @Override
    @Transactional
    public JSONObject updateUser(String Authorization, JSONObject jsonObject) {
        Date now = new Date();
        //修改使用用户id进行修改
        User user = JSONObject.toJavaObject(jsonObject, User.class);
        Long userId = jsonObject.getLong("userId");
        String password = jsonObject.getString("password");
        String str = jsonObject.getString("roleIds");
        if (userId == null) return JsonUtil.getFailJsonObject("请选择用户");
        if (user == null) return JsonUtil.getFailJsonObject("请填写完整信息");
        //获取完整的用户信息
        User tmp = selectById(userId);
        //修改用户信息
//        updateSelectiveById(user.toBuilder().updateTime(now).isSuperAdmin(null).deleteFlag(false).id(userId).build());
        user.setUpdateTime(now);
        user.setIsSuperAdmin(null);
        user.setDeleteFlag(false);
        user.setId(userId);
        try {
            updateSelectiveById(user);
        } catch (DuplicateKeyException e) {
            e.printStackTrace();
            return JsonUtil.getFailJsonObject("用户名已存在");
        }

        //更新证书信息
        Certificate certificate = new Certificate(jsonObject);
        updateCertificate(certificate, userId);
        //修改角色权限
        if (!StrUtil.isBlank(str)) {
            userRoleService.updateRoles(Authorization, StrUtil.getLongListByString(str,","), tmp);
        }
        //密码为空直接返回  如果不为空继续修改密码
        if (StrUtil.isBlank(password)) return JsonUtil.getSuccessJsonObject("修改成功");
        user.setKeycloakId(tmp.getKeycloakId());
        //如果之前没有创建用户
        if (StrUtil.isBlank(user.getKeycloakId())) {
            createUser(Authorization, password, user, StrUtil.isBlank(str) ? null :  StrUtil.getLongListByString(str,","));
            String keycloakId = getKeycloakIdUserInfoByUsername(Authorization, user.getUsername());
//            updateSelectiveById(User.builder().keycloakId(keycloakId).id(userId).build());
            User u = new User();
            u.setKeycloakId(keycloakId);
            u.setId(userId);
            updateSelectiveById(u);
//            redisService.putUserInfo(user.toBuilder().keycloakId(keycloakId).build());
            user.setKeycloakId(keycloakId);
            return JsonUtil.getSuccessJsonObject();
        } else {
            //如果二次增加密码这里处理
            JSONObject resultJsonObject = updatePassword(Authorization, user.getUsername(), password);
            int code = resultJsonObject.getInteger("code");
            if (code == 0) return JsonUtil.getSuccessJsonObject("修改成功");
            return JsonUtil.getFailJsonObject(String.valueOf(code), resultJsonObject.getString("msg"));
        }

    }


    /**
     * 更新用户证书信息  如果证书存在就更新证书   没有就创建证书
     *
     * @param certificate 证书文件信息
     * @param userId      用户id
     */
    public void updateCertificate(Certificate certificate, Long userId) {
        //修改证书信息
        certificate.setUpdateTime(new Date());
        //如果没有证书就进行添加
        if (certificateService.getByUserId(userId) == null) {
            certificateService.insertSelective(certificate);
        } else {
            certificateService.updateByUserId(certificate);
        }
    }

    @Override
    @Transactional
    public JSONObject addUser(String Authorization, JSONObject jsonObject) {
        Date now = new Date();
        if (jsonObject == null) return JsonUtil.getFailJsonObject("请注册单位信息");
        User user = JSONObject.toJavaObject(jsonObject, User.class);
        if (user == null) return JsonUtil.getFailJsonObject("请填写用户信息");
        if (StrUtil.isBlank(user.getName())) JsonUtil.getFailJsonObject("请输入姓名");
        if (StrUtil.isBlank(user.getSex())) JsonUtil.getFailJsonObject("请输入性别");
        if (StrUtil.isBlank(user.getEmail())) JsonUtil.getFailJsonObject("请输入邮箱");
        if (StrUtil.isBlank(user.getCellNumber())) JsonUtil.getFailJsonObject("请输入手机号");
        String str = jsonObject.getString("roleIds");
        if (StrUtil.isBlank(str)) return JsonUtil.getFailJsonObject("请选择角色");
        List<Long> roleIds =  StrUtil.getLongListByString(str,",");
        String companyName = jsonObject.getString("companyName");
        if (StrUtil.isBlank(companyName)) return JsonUtil.getFailJsonObject("请选择单位");
        if (ArrayUtil.isEmpty(roleIds)) return JsonUtil.getFailJsonObject("请选择角色");
        String username = user.getUsername().toLowerCase();
        user.setUsername(user.getUsername().toLowerCase());
        String password = jsonObject.getString("password");
        Long organizationId = jsonObject.getLong("organizationId");
        if (!StrUtil.isBlank(password) && !StrUtil.isBlank(user.getUsername())) {
            //创建keycloak账号
            JSONObject res = createUser(Authorization, password, user, roleIds);
            int code = res.getInteger("code");
            if (code != 0) return res;
        }
        //如果是注册那么就直接添加当前的组织架构然后添加当前的组织
        if (organizationId == null) {
            Organization organization = new Organization();
            organization.setName(companyName);
            organization.setLatitude(jsonObject.getDouble("latitude"));
            organization.setLongitude(jsonObject.getDouble("longitude"));
            organization.setRegion(jsonObject.getString("region"));
            organization.setCompanyId(jsonObject.getLong("companyId"));
            organization.setUsername(user.getUsername());
            organizationService.insertSelective(organization);
            organizationId = organization.getId();
        }
        //获取keycloak的id 添加到数据库
        String keycloakId = getKeycloakIdUserInfoByUsername(Authorization, user.getUsername());
        //添加用户
        user.setOrganizationId(organizationId);
        user.setKeycloakId(keycloakId);
        try {
            mapper.insertSelective(user);
        } catch (DuplicateKeyException e) {
            e.printStackTrace();
            return JsonUtil.getFailJsonObject("用户已存在");
        }

        Long userId = user.getId();
        //添加证书文件
        Certificate certificate = new Certificate(jsonObject);
        if (!StrUtil.isBlank(certificate.getCode())) certificateService.insert(certificate.toBuilder().createTime(now).updateTime(now).userId(user.getId()).build());
        List<UserRole> userRoles = new ArrayList<>();
        for (Long aLong : roleIds) {
//            UserRole.builder().userId(userId).roleId(aLong).createTime(now).updateTime(now).build();
            UserRole userRole = new UserRole();
            userRole.setUserId(userId);
            userRole.setRoleId(aLong);
            userRole.setCreateTime(now);
            userRole.setUpdateTime(now);
            userRoles.add(userRole);
        }
        userRoleService.insertList(userRoles);
        return JsonUtil.getSuccessJsonObject("注册成功");
    }


    @Override
    public JSONObject createUser(String Authorization, String password, User user, List<Long> roleIds) {
        JSONObject userJson = new JSONObject();
        userJson.put("username", user.getUsername());
        userJson.put("firstName", user.getName());
        userJson.put("password", password);
        //创建用户
//        JSONObject resultJson = iAuthService.createUser(Authorization, userJson);
        UserCreateQuery userCreateQuery=new UserCreateQuery();
        userCreateQuery.setUsername(user.getUsername());
        userCreateQuery.setFirstName(user.getName());
        userCreateQuery.setPassword(password);
        JSONObject resultJson=keycloakService.createUser(userCreateQuery,Authorization);
        int code = resultJson.getIntValue("code");
        //操作失败 返回用户中心返回的数据
        if (code != 0) {
            if (StateCode.ERROR_DATA_EXISTS.getCode() == code) {
                resultJson.put("msg", "登录账号已注册");
            }
            return resultJson;
        }
        String username = user.getUsername();
        String keycloakId = getKeycloakIdUserInfoByUsername(Authorization, username);
        if (ArrayUtil.isEmpty(roleIds)) return JsonUtil.getSuccessJsonObject();
        return createKeycloakUserPermission(Authorization, username, roleIds, keycloakId);
    }

    /**
     * 创建keycloak用户的权限信息
     * 1 -> 获取
     *
     * @param Authorization
     * @param username
     * @param roleIds
     * @return
     */
    public JSONObject createKeycloakUserPermission(String Authorization, String username, List<Long> roleIds, String keycloakId) {
        int code = -1;
        //获取刚注册用户的未分配的权限
        List<AdminClientRole> adminClientRoleList = getAvalableListByClientId(Authorization, clientId, keycloakId);
        //获取用户未分配的权限
        List<AdminClientRole> allocatedRoleList = new ArrayList<>();
        //创建完成用户之后我们需要为用户添加权限  用来存储所有的权限
        List<Permission> permissionList = permissionService.getListByRoleIds(roleIds);
        //创建一个list用来接收所有的权限名的值
        List<String> strList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(permissionList)) {
            //把所有的权限名的值都赋值到一个集合里面
            for (Permission permission : permissionList) {
                strList.add(permission.getName());
            }
        }
        //判断用户是否有这个权限有就把这个权限添加到用户中心
        for (AdminClientRole adminClientRole : adminClientRoleList) {
            if (strList.contains(adminClientRole.getName())) {
                allocatedRoleList.add(adminClientRole);
            }
        }
        //判断用户权限的集合是否为空不为空就直接添加到集合中
        if (!CollectionUtils.isEmpty(allocatedRoleList)) {
            log.info("添加的权限" + allocatedRoleList.toString());
            JSONObject resultObject = keycloakService.allocateRoles(allocatedRoleList,  keycloakId,clientId, Authorization);
            log.info("添加权限返回的json" + resultObject);
            code = resultObject.getIntValue("code");
            //添加失败
            if (code != 0) return JsonUtil.getFailJsonObject(resultObject.getString("msg"));
        }
        return JsonUtil.getSuccessJsonObject();
    }


    @Override
    public String getKeycloakIdUserInfoByUsername(String Authorization, String username) {
        JSONObject result = keycloakService.getUserInfoByUsername(Authorization, username);
        if (result == null) return null;
        int code = result.getInteger("code");
        if (code == 0) return result.getJSONObject("data").getString("userId");
        return null;
    }

    public String getToken(String mac, String username, String password) {
        JSONObject result = login(mac, username, password);
        if (0 == result.getInteger("code")) return result.getString("data");
        return null;
    }

    public JSONObject login(String mac, String username, String password) {
        JSONObject paramObj = new JSONObject();
        JSONObject attributesObj = new JSONObject();
        attributesObj.put("mac", mac);
        paramObj.put("realm", realm);
        paramObj.put("client", client);
        paramObj.put("username", username);
        paramObj.put("password", password);
        paramObj.put("clientSecret", clientSecret);
        paramObj.put("attributes", attributesObj);
//        JSONObject resultJsonObject = iAuthService.login(paramObj);
        JSONObject resultJsonObject = keycloakService.token(paramObj);
        int code = resultJsonObject.getIntValue("code");
        if (code == 0) {
            processLoginToken(username, resultJsonObject.getString("data"));
            return JsonUtil.getSuccessJsonObject(resultJsonObject.getString("data"));
        } else {
            return JsonUtil.getFailJsonObject(String.valueOf(code), resultJsonObject.getString("msg"));
        }
    }


    @Override
    public List<AdminClient> getClientList(String Authorization) {
        JSONObject jsonObject = keycloakService.getAvailableClientList(Authorization);
        int code = jsonObject.getIntValue("code");
        List<AdminClient> adminClientList = new ArrayList<>();
        if (code != 0) return null;
        JSONArray jsonArray = jsonObject.getJSONArray("data");
        if (ArrayUtil.isEmpty(jsonArray)) return null;
        for (Object obj : jsonArray) {
            JSONObject tmpObj = (JSONObject) obj;
            AdminClient adminClient = new AdminClient();
            adminClient.setId(tmpObj.getString("id"));
            adminClient.setClientId(tmpObj.getString("clientId"));
            adminClientList.add(adminClient);
        }
        return adminClientList;
    }

    @Override
    public List<AdminClientRole> getAvalableListByClientId(String Authorization, String clientId, String userId) {
        JSONObject jsonObject = keycloakService.getAvailableListByClientId(userId,clientId, Authorization);
        int code = jsonObject.getIntValue("code");
        List<AdminClientRole> adminClientRoleList = new ArrayList<>();
        if (code != 0) return null;
        JSONArray jsonArray = jsonObject.getJSONArray("data");
        if (ArrayUtil.isEmpty(jsonArray)) return null;
        adminClientRoleList = jsonArray.toJavaList(AdminClientRole.class);
        return adminClientRoleList;
    }

    @Override
    public User getUserByUsername(String username) {
        User u = new User();
        u.setUsername(username);
        return mapper.selectOne(u);
//        return mapper.selectOne(User.builder().username(username).build());

    }

    @Override
    public List<UserVO> getListByOrganizationId(Map<String, Object> map) {
        return mapper.getListByOrganizationId(map);
    }

    @Override
    public UserVO getUserVOByUsername(Map<String, Object> map) {
        return mapper.getUserVOByUsername(map);
    }

    @Override
    public UserVO getUserVOById(Map<String, Object> map) {
        return mapper.getUserVOById(map);
    }


    @Override
    public List<AdminClientRole> getListByClientId(String Authorization, String clientId) {
        JSONObject jsonObject = keycloakService.getListByClientId(Authorization, clientId);
        int code = jsonObject.getIntValue("code");
        List<AdminClientRole> adminClientRoleList = new ArrayList<>();
        if (code == 0) {
            JSONArray jsonArray = jsonObject.getJSONArray("data");
            if (jsonArray != null) {
                adminClientRoleList = jsonArray.toJavaList(AdminClientRole.class);
            }
        }
        return adminClientRoleList;
    }

    @Override
    @Transactional
    public JSONObject delUserByKeycloakId(String authorization, User user) {
//        User user = getUserByUsername(username);
        String keycloakId = user.getKeycloakId();
        if (user.getIsSuperAdmin()) {
            return JsonUtil.getFailJsonObject("无法删除管理员用户");
        }
        delById(user.getId());
        //删除keycloak信息
        if (!StrUtil.isBlank(keycloakId)) {
            keycloakService.delUser(authorization, keycloakId);
        }
        //删除用户角色关联关系
        UserRole userRole = new UserRole();
        userRole.setUserId(user.getId());
        userRoleService.delete(userRole);
        return JsonUtil.getSuccessJsonObject("删除成功");
    }


//    @Override
//    public JSONObject delUserById(String authorization, Long id) {
//        User user = selectById(id);
//        if (user == null) return JsonUtil.getFailJsonObject("请选择用户");
//        String keycloakId = user.getKeycloakId();
//        if (user.getIsSuperAdmin()) {
//            return JsonUtil.getFailJsonObject("无法删除管理员用户");
//        }
//        delById(user.getId());
//        //删除keycloak信息
//        if (!StrUtil.isBlank(keycloakId)) {
//            keycloakService.delUser(authorization, keycloakId);
//        }
//        //删除用户角色关联关系
//        UserRole userRole = new UserRole();
//        userRole.setUserId(user.getId());
//        userRoleService.delete(userRole);
//        return JsonUtil.getSuccessJsonObject("删除成功");
//    }

    @Override
    public Integer delById(Long id) {
        User u = new User();
        u.setId(id);
        u.setDeleteFlag(true);
        return updateSelectiveById(u);
//        return updateSelectiveById(User.builder().id(id).deleteFlag(true).build());
    }


    @Override
    public List<User> getListByRoleId(Long roleId) {
        Map<String, Object> map = new HashMap<>();
        map.put("roleId", roleId);
        return mapper.getListByRoleId(map);
    }

    @Override
    public List<UserVO> getListByLike(Map<String, Object> map) {
        return mapper.getListByLike(map);
    }


    /*
  logoutMode:退出模式，1：正常操作登出退出，2.强制退出，即被挤掉，3：超时退出
   */
    @Override
    public JSONObject logout(String username, String token, int logoutMode) {
//        JSONObject resultJsonObject = keycloakService.logout(token);
        JSONObject resultJsonObject = keycloakService.invalidateToken(token);
        int code = resultJsonObject.getIntValue("code");
        UserAudit userAudit = userAuditService.getByUsernameAndToken(username, token);
        if (code == 0) {
            if (userAudit != null) {
                userAudit.setLogoutTime(new Date());
                if (logoutMode == 1) {
                    userAudit.setRemark("正常退出");
                } else if (logoutMode == 2) {
                    userAudit.setRemark("其他地方登录，被挤掉");
                } else if (logoutMode == 3) {
                    userAudit.setRemark("超时没操作自动退出");
                }

                userAuditService.updateById(userAudit);
            }
            //删除redis中记录
            redisService.mapDelete(UserConstant.tokenUserMap,token);
            Set<String> tokens = (Set<String>) redisService.mapGet(UserConstant.userTokenMap, username);
//            TokenInfo tmpTokenInfo = null;
            if (!CollectionUtils.isEmpty(tokens)) {
                for (String token1 : tokens) {
                    if (token1.equals(token)) {
                        tokens.remove(token1);
                        redisService.mapPut(UserConstant.userTokenMap, username, tokens);
                        break;
                    }
                }
            }
            return JsonUtil.getSuccessJsonObject(resultJsonObject.getString("data"));
        } else {
            return JsonUtil.getFailJsonObject(Integer.valueOf(code), resultJsonObject.getString("msg"));
        }
    }


    @Override
    public boolean clearAccessToken(String username) {
        String token = redisService.getStringValue(username);
        if (token == null) {//如果其他地方有用户登录，则强制退出
            return true;
        }
        JSONObject jsonObject = logout(username, token, 2);
        if (jsonObject.getIntValue("code") == 0) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    @Transactional
    public JSONObject registerUser(JSONObject jsonObject) {
        Company company = jsonObject.toJavaObject(jsonObject, Company.class);
        JSONObject res = null;
        try {
            res = companyService.addCompany(company);
        } catch (DuplicateKeyException e) {
            e.printStackTrace();
            return JsonUtil.getFailJsonObject("单位已存在请勿重复添加");
        }
        String c = res.getString("code");
        if ("1".equals(c)) {
            return res;
        }
        JSONObject userJson = jsonObject.getJSONObject("user");
        userJson.put("companyId", company.getId());
        userJson.put("companyName", company.getName());
        String Authorization = getToken("", systemUsername, systemPassword);
        JSONObject result = addUser(Authorization, userJson);
        String code = result.getString("code");
        if ("1".equals(code)) {
            companyService.deleteById(company.getId());
        }
        return result;
    }

    @Override
    public boolean processLoginToken(String username, String token) {
        try {
            //获取用户和token的对应关系，一对多
            Set<String> tokens = (Set<String>) redisService.mapGet(UserConstant.userTokenMap, username);
            if (CollectionUtils.isEmpty(tokens)) {
                tokens = new HashSet<>();
            }

            User user = getUserByUsername(username);
            Company company = companyService.selectById(user.getCompanyId());

            TokenInfo tokenInfo = new TokenInfo();
            tokenInfo.setUsername(username);
            tokenInfo.setToken(token);
            tokenInfo.setLastTime(new Date());
            tokenInfo.setName(user.getName());
            tokenInfo.setCompanyId(user.getCompanyId());
            tokenInfo.setCompanyName(company.getName());
            tokenInfo.setObisDefine(company.getObisDefine());
            redisService.mapPut(UserConstant.tokenUserMap,token,tokenInfo);


            Boolean bSingleUserLogin = user.getSingleUserLogin()==null?true:user.getSingleUserLogin();
            if (bSingleUserLogin) {//如果是单用户，要把其他用户
                //把其他用户登出
                for (String token1 : tokens) {
                    logout(tokenInfo.getUsername(), token1, 2);
                }
                tokens.clear();
            }
            tokens.add(token);
            redisService.mapPut(UserConstant.userTokenMap, username, tokens);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return false;
    }

    @Override
    public JSONObject isAccessToken(String Authorization) {
        KeycloakUser keycloakUser=null;
        try {
            keycloakUser=keycloakService.generateUser(Authorization);
        }catch (FeignRequestException fre){
            if(fre.getStatus()==401){
                return JsonUtil.getFailJsonObject(StateCode.INVALID_TOKEN.getCode(),StateCode.INVALID_TOKEN.getMsg());
            }else{
                return JsonUtil.getFailJsonObject(fre.getStatus(), KeycloakUtil.getMsg(fre));
            }
        }catch (Exception e) {
            return JsonUtil.getFailJsonObject(KeycloakUtil.getMsg(e));
        }
        User user=getUserByUsername(keycloakUser.getUsername());
        Boolean isAccessToken=keycloakService.isAccessToken(Authorization,user);
        JSONObject jsonObject=new JSONObject();
        jsonObject.put("isAccessToken", isAccessToken);
        return JsonUtil.getSuccessJsonObject(jsonObject);
    }


}